﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.SqlClient;
using System.Linq;
using System.Linq.Expressions;
using System.Runtime.Caching;
using System.Text;

namespace System.Data
{
    /// <summary>
    /// 此类的实现还不是很好,暂时不要直接使用此类
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <typeparam name="TDbContext"></typeparam>
    public sealed class EntityCache<TEntity, TDbContext> : IDisposable
        where TDbContext : GenericDbContext, new()
        where TEntity : BaseEntity
    {
        private IDbContext _context;

        public EntityCache()
        {

        }

        private readonly string _cacheKey = Guid.NewGuid().ToString();

        private IEnumerable<TEntity> GetCurrent(Expression<Func<TEntity, bool>> predicate)
        {
            if (_context == null)
            {
                _context = new TDbContext();
            }
            var query = _context.Set<TEntity>().Where(predicate);

            return query;
        }

        /// <summary>
        /// 从数据库中获取数据并缓存
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public IEnumerable<TEntity> GetResults(Expression<Func<TEntity, bool>> predicate)
        {
            var value = MemoryCache.Default[_cacheKey] as List<TEntity>;
            if (value == null)
            {
                value = GetCurrent(predicate).ToList();
                var changeMonitor = new EntityChangeMonitor<TEntity, TDbContext>(predicate);
                var policy = new CacheItemPolicy();
                policy.SlidingExpiration = TimeSpan.FromMinutes(5);
                policy.ChangeMonitors.Add(changeMonitor);
                MemoryCache.Default.Add(_cacheKey, value, policy);
                Console.WriteLine("From Database...");
            }
            else
            {
                Console.WriteLine("From Cache...");
            }
            return value;
        }


        private void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_context != null)
                {
                    _context.Dispose();
                    _context = null;
                }
            }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    }
}